--- Provides the 'Token' type and associated instances and low level functions.
module frege.compiler.types.Tokens where 

import  frege.compiler.enums.TokenID

--- line numbers
type Line = Int


--- numbers that tell on which column a token started, 1 based
type Indent = Int


--- offset in characters from the beginning of something, 0 based
type Offset = Int


--- the data structure for tokens along with string, line and column info
data Token = Token  { !tokid  :: TokenID,
                      !value  :: String,
                      !line   :: Line,
                      !col    :: Indent,
                      !offset :: Offset    --- offset in characters, 0 originated at beginning of source code
                      !qual   :: [Token]   --- up to 2 tokens that are CONID, qualifying an operator (only!)
                       } where
    --- Is @true@ if the token is a 'COMMENT'
    isComment Token{tokid}     = tokid == COMMENT
    --- Is @true@ if the token is not a 'COMMENT'
    noComment Token{tokid}     = tokid != COMMENT
    -- position  tok              = Pos tok tok
    --- check if first token is followed without space by second
    vor :: Token -> Token -> Bool
    vor t1 t2 = t1.line == t2.line &&
            (t1.tokid == CHAR && (t1.col + 1) == t2.col ||
             t1.tokid == QUALIFIER && (t1.col + t1.length + 1) == t2.col ||
             t1.tokid != CHAR && (t1.col + t1.length) == t2.col)
    length Token{tokid, value} = case tokid of
        REGEXP    -> 2 + value.length
        -- QUALIFIER -> 1 + value.length
        sonst     -> value.length


derive Show Token


instance Eq Token where
    t1 == t2 = t1.tokid == t2.tokid
                && t1.value  == t2.value
                && t1.line   == t2.line
                && t1.col    == t2.col
                && t1.offset == t2.offset
    hashCode Token{tokid,value,line,col,offset} 
        = (((hashCode tokid*31 + hashCode value) * 31 + hashCode line) * 31 + hashCode col) * 31 + hashCode offset


--- Wrapper on Token to impose an ordering based on offsets 
newtype KeyToken = KeyTk Token


instance Ord KeyToken where
    hashCode (KeyTk t) = hashCode t
    KeyTk t1 <=> KeyTk t2 = case t1.offset <=> t2.offset of
        Eq -> (t1.tokid, t1.value) <=> (t2.tokid, t2.value)
        ordering -> ordering


derive ArrayElement Token




prelToken = Token CONID "Prelude" 1 0 0 []



{-- 
    produces a 'CONID' token with value "PreludeBase"
    that appears seemingly to occur where the argument token is.

    Used to construct qualified source names. 
-}
baseTokenAt Token{line, col, offset} = baseToken.{line,col,offset}
private baseToken = Token CONID "PreludeBase" 1 0 0 []


listToken = Token CONID "PreludeList" 1 0 0 []


monadToken = Token CONID "PreludeMonad" 1 0 0 []


underlineToken = Token VARID "_" 1 0 0 []




--- extract first character of token value
cval :: Token -> Char
cval t = t.value.charAt 0


